<?php

namespace System\library\logger\writers;

use System\library\Logger;
use System\library\Debugger;

/**
 * <b>Class</b> :        File<br>
 * <b>Fonction</b> :     Writer "File" pour le logger, permet d'écrire les logs
 * <br>
 * @version              1.0
 * @author               Dread <dreadlokeur@gmail.com>
 * @license              Licence publique générale GNU http://www.gnu.org/licenses/gpl.html
 * @copyright            Copyright 2011 - MidichloriansPHP and contributors
 * @package              System
 * @subpackage           library\logger\writers
 *
 * @see \SplObserver
 */
class File implements \SplObserver {

    private $_logDir;
    private $_logFileName;
    private $_logs = array();
    private $_formater;

    public function __construct($logDir, $logFileName = 'log') {
        $this->setLogDir($logDir, true);
        $this->setLogFileName($logFileName);
        $this->_formater = Logger::getFormater();
    }

    public function __destruct() {
        $this->_writeLogs();
    }

    public function getFormater() {
        return Logger::getFormater();
    }

    private function _writeLogs() {
        Debugger::dump($this->_logs);
        $dir = $this->_selectLogDir();
        $logExt = $this->_formater->getFormaterName();
        if (file_exists($dir . $this->_logFileName . '-' . date('d') . '.' . $logExt)) {
            // Le log existe, donc on va placer le cursor juste avant la footer, inserer les logs...
        } else {
            $file = new \SplFileObject($dir . $this->_logFileName . '-' . date('d') . '.' . $logExt, 'a+');
            if ($file->flock(LOCK_EX)) {
                $data = $this->_formater->getHeader();
                $data .= $this->_formater->format($this->_logs);
                $data .= $this->_formater->getFooter();
                if ($this->getFormater()->getIndente())
                    $data = $this->_formater->indente($data);
                $file->fwrite($data);
                $file->flock(LOCK_UN);
            }
        }
    }

    private function _selectLogDir() {
        $yearDir = $this->_logDir . date('Y');
        if (!is_dir($yearDir)) {
            if (!mkdir($yearDir, '0775', true))
                throw new \Exception('Error on creating "' . $yearDir . '" directory');
        }
        $monthDir = $yearDir . DIRECTORY_SEPARATOR . date('m') . DIRECTORY_SEPARATOR;
        if (!is_dir($monthDir)) {
            if (!mkdir($monthDir, '0775', true))
                throw new \Exception('Error on creating "' . $monthDir . '" directory');
        }
        return $monthDir;
    }

    public function setLogDir($dir, $forceCreate = false) {
        if ($forceCreate && !is_dir($dir)) {
            if (!mkdir($dir, '0775', true))
                throw new \Exception('Error on creating "' . $dir . '" directory');
        }else {
            if (!is_dir($dir))
                throw new \Exception('Directory "' . $dir . '" do not exists');
        }
        if (!is_writable($dir))
            throw new \Exception('Directory "' . $dir . '" is not writable');
        $this->_logDir = realpath($dir) . DIRECTORY_SEPARATOR;
        return $this;
    }

    public function setLogFileName($logFileName) {
        if (!is_string($logFileName))
            throw new \Exception('The filename must be a string');
        $this->_logFileName = $logFileName;
        return $this;
    }

    public function update(\SplSubject $subject, $lastLogOnly = false, $bottomLogs = false) {
        $logs = ($bottomLogs) ? $bottomLogs : $subject->getLogs();
        $groups = $subject->getGroups();
        // Recuperation du dernier log
        if ($lastLogOnly) {
            $lastLog = array();
            $lastLog[] = end($logs);
            $logs = $lastLog;
        }
        $bottomLogs = array();
        // Traitement des logs
        foreach ($logs as &$log) {
            if (is_array($log)) {
                if ($groups[$log[0]->group]->onBottom) {
                    $groups[$log[0]->group]->onBottom = false;
                    $bottomLogs[] = $log;
                } else {
                    $this->_addGroupTop($log[0]->date, $groups[$log[0]->group]->label);
                    foreach ($log as &$l)
                        $this->_addLog($l->message, $l->level, $l->date, true);
                    $this->_addGroupBottom($l->date);
                }
            } else
                $this->_addLog($log->message, $log->level, $log->date);
        }
        if (count($bottomLogs) > 0)
            $this->update($subject, false, $bottomLogs);
    }

    private function _addLog($message, $level, $date, $groupLog = false) {
        $this->_logs[] = array('date' => $date, 'level' => Logger::getLevelName($level), 'message' => $message, 'groupTitle' => false, 'groupLog' => ($groupLog) ? : true, false);
    }

    private function _addGroupTop($date, $label) {
        //$this->_log[] = '[' . $date . '][GROUP]' . str_pad($label, 100, '-', STR_PAD_BOTH);
        $this->_logs[] = array('date' => $date, 'level' => 'GROUP', 'message' => $label, 'groupTitle' => true, 'groupLog' => false);
    }

    private function _addGroupBottom($date) {
        //$this->_log[] = '[' . $date . '][GROUP]' . str_repeat('-', 102);
    }

}

?>
